import { customRef, type Ref } from "vue";
import EventChannel from "async-event-channel";
import dayjs, { type ConfigType } from "dayjs";
import { getDictType } from "/api/training";

const systemInfo = uni.getSystemInfoSync();

uni.$EventChannel = EventChannel;

// 全局事件通道
uni.$appEventChannel = new EventChannel();

// 状态栏高度
uni.$statusBarHeight = systemInfo.statusBarHeight;

// 状态栏+导航栏高度
uni.$navBarHeight = systemInfo.statusBarHeight + 44;

// rpx转px
uni.$rpxToPx = (() => {
  const rate = systemInfo.screenWidth / 750;
  return (rpx: number) => rpx * rate;
})();

// easyinput组件属性
uni.$easyinput_attrs = {
  inputBorder: false,
  placeholderStyle: "color: #6B7280;font-size: 24rpx;",
  primaryColor: "#c0c4cc",
  clearSize: 20,
};

/**
 * 获取字典数据
 * @param key 字典键
 * @param value 字典值
 * @param options 可选参数
 * @param options.noCache 是否不使用缓存
 * @param options.default 默认值
 * @returns 返回异步字典标签
 */
uni.$useDict = (() => {
  type Dict = {
    dictValue: string | number;
    dictLabel?: string;
  }[];
  const cache = new Map<string, Promise<Dict>>();
  return (
    key: string,
    value: string | number,
    {
      noCache = false,
      default: defaultValue = "--",
    }: { noCache?: boolean; default?: string } = {}
  ) => {
    if (!cache.has(key) || noCache) {
      const dict = getDictType(key)
        .then((res) => res?.data || [])
        .catch(() => {
          cache.delete(key);
          return [];
        });
      cache.set(key, dict);
    }
    return cache.get(key)!.then((dict) => {
      const result = dict.find(({ dictValue }) => dictValue == value);
      return result ? result.dictLabel : defaultValue;
    });
  };
})();

/**
 * 格式化时间-最近时间
 * @param val 要格式化的时间
 * @returns 格式化后的时间
 */
uni.$formatLatelyTime = (val: ConfigType) => {
  if (!val) return "";
  const current = dayjs();
  const target = dayjs(val);
  const offsetDay = dayjs(current.format("YYYY-MM-DD")).diff(
    dayjs(target.format("YYYY-MM-DD")),
    "day"
  );
  if (offsetDay < 1) {
    // 今天
    return target.format("HH:mm");
  }
  if (offsetDay < 2) {
    // 昨天
    return `昨天 ${target.format("HH:mm")}`;
  }
  const currentDay = current.day() || 7;
  if (offsetDay < currentDay) {
    // 本周
    return target.format("dddd HH:mm");
  }
  if (current.format("YYYY") === target.format("YYYY")) {
    // 本年
    return target.format("MM-DD HH:mm");
  }
  return target.format("YYYY-MM-DD HH:mm");
};

/**
 * Promise防抖
 * @see 防抖后的Promise会保留最后一次的结果
 * @param promise 要防抖的Promise
 * @returns 防抖后的Promise
 */
uni.$usePromiseDebounce = () => {
  let _reject: (reason?: any) => void = () => {};
  return <T extends Promise<any>>(promise: T): T =>
    new Promise((resolve, reject) => {
      _reject("PromiseDebounce: canceled");
      _reject = reject;
      promise.then(resolve, reject);
    }) as T;
};

/**
 * 全局 loading
 */
uni.$useLoading = () =>
  customRef((track, trigger) => {
    let count = 0;
    return {
      get() {
        track();
        return count > 0;
      },
      set(value) {
        if (value) {
          count++;
        } else {
          count = Math.max(0, count - 1);
        }
        trigger();
      },
    };
  });

/**
 * 全局防抖 loading
 */
uni.$useDebounceLoading = <T extends Array<(...args: any[]) => Promise<any>>>(
  ...fns: T
) => {
  const loading = uni.$useLoading();
  const result = fns.map((fn) => {
    const promiseDebounce = uni.$usePromiseDebounce();
    return async (...args: any[]) => {
      loading.value = true;
      try {
        return await promiseDebounce(fn(...args));
      } finally {
        loading.value = false;
      }
    };
  });
  return [loading, ...result] as [Ref<boolean>, ...T];
};

/**
 * 校验是否为数字
 * @param val 需要校验的值
 * @returns 校验结果
 */
uni.$isNumeric = (value: unknown) =>
  !isNaN(parseFloat(value as string)) && isFinite(value as number);
